﻿using Emgu.CV;
using Emgu.CV.Structure;
using Emgu.CV.Util;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Emgu.CV.CvEnum;
using System.Drawing;
using System.Drawing.Drawing2D;
namespace OpencvProjectBase.EmguHelper.Blob
{
    public class AdvanceBlob
    {

        #region 二值化
        /// <summary>
        /// 提取指定阈值范围内或外的区域<br>
        /// 仿halcon的threshold</br>
        /// </summary>
        /// <returns>只有roi的原图叠加</returns>
        public Mat ThresholdMinMax(Mat src, int min, int max)
        {
            Mat dst1 = new Mat();
            Mat dst2 = new Mat();

            CvInvoke.Threshold(src, dst1, max, 255, Emgu.CV.CvEnum.ThresholdType.BinaryInv);
            //CvInvoke.Imshow("dst1", dst1);
            CvInvoke.Threshold(src, dst2, min, 255, Emgu.CV.CvEnum.ThresholdType.BinaryInv);
            //CvInvoke.Imshow("dst2", dst2);

            Mat dst = dst1 - dst2;

            return dst;

        }
        /// <summary>
        /// 提取指定阈值范围内或外的区域,并指定roi填充色<br>
        /// 仿halcon的threshold</br>
        /// </summary>
        /// <returns>只有roi的原图叠加</returns>
        public Mat ThresholdMinMax(Mat src, int min, int max, Color color)
        {
            return new Mat();
        } 
        #endregion

        public void FindContour()
        {
            //VectorOfVectorOfPoint vvp = new VectorOfVectorOfPoint();//存放的数据点
            //Mat mat = new Mat();
            //Mat src1= src.Clone();
            //CvInvoke.FindContours(src1, vvp, mat, RetrType.External, ChainApproxMethod.ChainApproxSimple);
            //CvInvoke.DrawContours(src1, vvp, 2, new MCvScalar(0, 0, 255));
            //CvInvoke.Imshow("coutour", src);
        }

        public List<Mat> Connection(Mat src,out Mat dstRaw)
        {
            //Matrix<byte> a=new Matrix<byte>(src.Rows,src.Cols,src.Ptr);
            //var t = a.Data[2,1];

            
            
            List<Mat> ret = new List<Mat>();
            Mat dst = new Mat();
            src.ConvertTo(dst, DepthType.Cv8U);
            Mat stats = new Mat();
            Mat cent= new Mat();
            //var res = CvInvoke.ConnectedComponentsWithStats(src, dst,stats,cent);
            

            //for (int i = 0; i < stats.Rows; i++)
            //{
            //    rects.Add(new Rectangle(stats.));
            //}  
            var res = CvInvoke.ConnectedComponents(src, dst);
            //List<Rectangle> rects = new List<Rectangle>();
            //var s = stats.ToImage<Gray, byte>();
            dst.ConvertTo(dst, DepthType.Cv8U);
            dst = dst + 200;

            Mat zeros = dst - dst; //Create a matrix of zeros (with same type as markers).
            
            CvInvoke.Imshow("labelImg", dst);

            var elem = dst.Split();
            dstRaw = dst;
            //CvInvoke.Imshow("1", elem[0]);
            //CvInvoke.Imshow("2", elem[1]);
            //CvInvoke.Imshow("3", elem[2]);
            
            return ret;
        }
        public void Ts()
        {
            //ret, thresh = cv2.threshold(gray,0,255,cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)
            var img = new Image<Bgr, byte>(@"test.bmp");

            //var mask = img.Convert<Gray, byte>().ThresholdBinary(new Gray(100), new Gray(255));
            //https://stackoverflow.com/a/25994631/4926757
            Image<Gray, byte> gray = img.Convert<Gray, byte>();
            CvInvoke.Imshow("gray", gray);
            Image<Gray, byte> thresh = gray.CopyBlank();
            CvInvoke.Imshow("grayCopyBlank", thresh);

            CvInvoke.Threshold(gray, thresh, 200, 255, Emgu.CV.CvEnum.ThresholdType.Binary | Emgu.CV.CvEnum.ThresholdType.Otsu);

            CvInvoke.Imshow("thresh", thresh);

            Matrix<byte> kernel = new Matrix<byte>(new Byte[3, 3] { { 1, 1, 1 }, { 1, 1, 1 }, { 1, 1, 1 } }); //https://stackoverflow.com/a/33646626/4926757
            Image<Gray, Byte> opening = thresh.MorphologyEx(Emgu.CV.CvEnum.MorphOp.Open, kernel, new Point(-1, -1), 2, Emgu.CV.CvEnum.BorderType.Default, new MCvScalar());
            Image<Gray, Byte> sureBg = opening.Dilate(3);

            Mat distanceTransform = new Mat();
            CvInvoke.DistanceTransform(opening, distanceTransform, null, Emgu.CV.CvEnum.DistType.L2, 5);

            double minVal = 0, maxVal = 0;
            Point minLoc = new Point(), maxLoc = new Point();
            CvInvoke.MinMaxLoc(distanceTransform, ref minVal, ref maxVal, ref minLoc, ref maxLoc);  //Find distanceTransform.max()

            Mat sureFg0 = new Mat();
            CvInvoke.Threshold(distanceTransform, sureFg0, 0.2 * maxVal, 255, Emgu.CV.CvEnum.ThresholdType.Binary);
            CvInvoke.Imshow("sureFg0", sureFg0);
            Mat sureFg = new Mat();
            sureFg0.ConvertTo(sureFg, Emgu.CV.CvEnum.DepthType.Cv8U); //Convert from float to Byte
            CvInvoke.Imshow("sureFg", sureFg);
            Mat unknown = new Mat();
            CvInvoke.Subtract(sureBg, sureFg, unknown);

            
            Mat markers = new Mat();
            CvInvoke.ConnectedComponents(sureFg, markers);
            //CvInvoke.Imshow("markers", markers);

            markers = markers + 1;

            Mat zeros = markers - markers;
            Mat uncopy = new Mat();
                unknown.CopyTo(uncopy);
            CvInvoke.Imshow("unknown", unknown);
            zeros.CopyTo(markers, unknown); 

            CvInvoke.Imshow("unknown1", unknown);

         
            //Mat finalMarkers = new Mat();
            //CvInvoke.Watershed(img, markers);

            Mat mask = new Mat();
            zeros.SetTo(new MCvScalar(-1)); 
            CvInvoke.Compare(markers, zeros, mask, CmpType.Equal);
            mask.ConvertTo(mask, Emgu.CV.CvEnum.DepthType.Cv8U); 
            Mat blue = new Mat(img.Rows, img.Cols, Emgu.CV.CvEnum.DepthType.Cv8U, 3);
            blue.SetTo(new MCvScalar(255, 0, 0)); 
            blue.CopyTo(img, mask);

            CvInvoke.Imshow("mask", mask);
            CvInvoke.Imshow("img", img);
            CvInvoke.WaitKey();


            CvInvoke.Imwrite("mask.png", mask);
            CvInvoke.Imwrite("img.png", img); 
        }
    }
}
